#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cstring>
using namespace std;

//匿名管道通信
int main()
{
    //向操作系统申请匿名管道缓冲区，开放读写端
    //为什么开放读写段？ 为了让子进程也获取读写端，便以实现单向管道通信
    int fds[2];
    int ret = pipe(fds);
    assert(ret == 0);
    //fds[0] -> 读的文件描述符
    //fds[1] -> 写的文件描述符


    //实现单向通行  子进程进行写，父进程进行读
    pid_t id = fork(); 
    if(id == 0)
    {
        //子进程  -> 关闭读端
        close(fds[0]);

        //开始进程通信
        char buffer[1024];
        int cnt = 0;
        while(true)
        {
            //当子进程快速向管道写数据，而父进程缓慢的读取数据，管道具有一定大小的空间
            //此时管道可能会被写满，而父进程还没有读取，此时操作系统会停止子进程继续写入数据，
            //等待缓冲区有余留的空间时才继续写入数据
            cnt++;
            cout << "aaaaaaaa" << endl;
            snprintf(buffer, sizeof buffer, "子进程正在进行发送信息 [%d] pid :[%d]", cnt, getpid());
            write(fds[1], buffer, strlen(buffer));
            sleep(1);
            ////慢写
            //sleep(3);

            // //当写端关闭时，读端读完管道后返回0，取消阻塞等待状态
             close(fds[1]);
             break;
        }
        exit(1);
    }
    //父进程 -> 关闭写端
    close(fds[1]);

    //开始进程通信
    char buffer[1024];
    while(true)
    {
        //当子进程进行缓慢写，而父进程快速读取的时候，管道可能还没有被写入数据
        //此时父进程不会继续执行自己的代码，父进程会进行阻塞式读取
        cout << "aaaaaaa" << endl;
        ssize_t num = read(fds[0], buffer, sizeof(buffer) - 1); //为缓冲区预留空间防止\0添加失败
        cout << "bbbbbbb" << endl;
        //assert(num != 0);
        buffer[num] = 0;
        if(num > 0)
        {
            cout << buffer << endl;
        }
        if(num == 0)
        {
            cout << "read: " << num << endl;
            break;
        }
        // //缓慢读取管道数据
        // sleep(10000);
        //当读端关闭时，写端再写数据就没有意义了，操作系统会发信号终止写端进程
        //close(fds[0]);
        //break;
    }
    int status;
    ret = waitpid(id, &status, 0);
    assert(ret == id);
    cout << "wait success" << " exit sig:" << (status & 0x7f) << endl;
    return 0;
}